home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
p063b9s.zip
/
UNIT
/
JANUS.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1997-03-02
|
45KB
|
1,435 lines
UNIT Janus;
{╔══════════════════════════════════════════════════════════════════════════╗}
{║ Janus transfer protocol Last changed: 02.03.97 SA ║}
{║ ║}
{║ (C) Copyright 1989-97 by ║}
{║ Dan Wulff, Jens Sandalgaard, Steen Christensen & S¢ren Ager ║}
{║ ║}
{║ This source may not be given to anybody, without the written permission ║}
{║ from The Portal Team. ║}
{╚══════════════════════════════════════════════════════════════════════════╝}
{$I POPDEFS.INC}
INTERFACE
USES Use32;
PROCEDURE DoJanus;
IMPLEMENTATION
USES Dos, OpCrt, OpRoot, OpDate, OpString, OpDos, ApTimer,
PoPTypes, Globals, StrUtil, FileUtil, MailUtil, Com, ZMisc, UnixDate,
Crc, Util, MTask, ParseReq, PTpl, TransVid, LogFile, NetFile, SimpDB,
Event, OproUtil;
PROCEDURE DoJanus;
LABEL
GiveUp, abort, BreakOut;
CONST
DLE = $10;
BUFMAX = 2048;
NUMFLAGS = 5;
XDONE = 0;
XSENDFNAME = 1;
XRCVFNACK = 2;
XSENDBLK = 3;
XRCVEOFACK = 4;
XSENDFREQNAK = 5;
XRCVFRNAKACK = 6;
RDONE = 0;
RRCVFNAME = 1;
RRCVBLK = 2;
NOPKT = 0;
BADPKT = Byte('@');
FNAMEPKT = Byte('A');
FNACKPKT = Byte('B');
BLKPKT = Byte('C');
RPOSPKT = Byte('D');
EOFACKPKT = Byte('E');
HALTPKT = Byte('F');
HALTACKPKT = Byte('G');
FREQPKT = Byte('H'); { File Request Packet }
FREQNAKPKT = Byte('I');
FRNAKACKPKT = Byte('J');
BUFEMPTY = -1;
PKTSTRT = -2;
PKTEND = -3;
NOCARRIER = -4;
PKTSTRT32 = -5;
PKTSTRTCHR = Byte('a');
PKTENDCHR = Byte('b');
PKTSTRTCHR32 = Byte('c');
GOODXFER = 0;
FAILEDXFER = 1;
INITIALXFER = 2;
ABORTXFER = 3;
SENDRSPFILE = 4;
CANCRC32 = $80;
CANFREQ = $40;
TYPE
BufferType = ARRAY[0..5000] Of Byte;
VAR
OURCAP, BadXFers, LastSent : Byte;
RxCRC32 : BOOLEAN;
p, rcrc16 : WORD;
rcrc32 : LongInt;
OutboundName : PathStr;
FloFlag : Boolean;
FloNamePos : LongInt;
fn, s : PathStr;
AttemptingReq,ReqStarted, SendingReq,
TxInhibit, MustWriteDRI : Boolean;
i, PktType : Integer;
SAddress, OAddress, ReqAddress : TFidoAddress;
RxBufMax, RxBlkLen, BlkLen, TxBlkLen, TxBlkMax,
GoodNeeded, GoodBytes, RPosCount, Days : Word;
XMitRetry, BrainDead, RPosRetry : EventTimer;
Secs, TxPos, LastTx, TxStPos,
RxStPos, TxLen,
TotalBytes, DiskAvail, RxLen, RxFileTime,
TimeOutSecs, RposStTime, LastRPosTime,
LastBlkPos : LongInt;
ReqFile : PBufTextFile;
Effektivitet : Real;
BusyFile, FloFile, TxFile, RxFile : File;
TxBuf, RxBuf : Pointer;
ReqAkaNum, RState, XState, WaitFlag, AkaNum,
SharedCap : Byte;
RxDt1, TxDt1, StartTime : DateTimeRec;
TxFName, RxFName : String;
DoAfter : Char;
FreeArea : TFreeArea;
PROCEDURE Time(VAR t:LONGINT);
VAR
y,m,d,dofw,hour,min,sec,sec100:WORD;
BEGIN
{$IFDEF JDebug}
FastWrite('Time ',1,1,7);
{$ENDIF}
GetDate(y,m,d,dofw);
GetTime(hour,min,sec,sec100);
t:=GetUnixDate(y,m,d,hour,min,sec);
{$IFDEF JDebug}
FastWrite('END Time ',1,1,7);
{$ENDIF}
END;
PROCEDURE GetFName(XFerFlag: WORD);
LABEL
DoItAgain,SkipName, Abort, NxtOut, RdFLO, SendIt, SendIt2, NextAka;
VAR
dt : DateTime;
s, HoldName : PathStr;
CurrPos : LongInt;
i : Byte;
f : SEARCHREC;
Ch : Char;
BEGIN
{$IFDEF JDebug}
FastWrite('GetFName ',1,1,7);
{$ENDIF}
DoItAgain:
IF XFerFlag=InitialXFer THEN
BEGIN
FLOFlag:=FALSE;
OutboundName:='';
DoAfter:=NothingAfter;
BadXFers:=0;
FloNamePos:=0;
IF NOT MarkNodeBusy(BusyFile, Call) THEN
BEGIN
AddLog(':',Address2Str(Call)+' is marked busy - skipping');
GOTO NextAka;
END;
END ELSE
BEGIN
IF (CurrentEvent.typ AND etNoSend)=etNoSend THEN
BEGIN
Integer(TxBuf^):=0;
UnMarkNodeBusy(BusyFile);
Exit;
END;
IF FileRec(TxFile).Mode<>fmclosed THEN
BEGIN
CLOSE(TxFile);
IF XFerFlag=GoodXFer THEN
BEGIN
CASE DoAfter OF
DeleteAfter,
ShowDeleteAfter : BEGIN
IF DoAfter=ShowDeleteAfter THEN
AddLog('!','Unlinking '+TxFName);
DeleteFile(TxFName);
END;
TruncAfter : BEGIN
AddLog('!','Flagging '+TxFName+' as sent');
TruncateFile(TxFName);
END;
END;
SkipName:
IF FLOFlag THEN
BEGIN
IF (DoAfter<>NothingAfterRefuse) THEN
BEGIN
CurrPos:=FilePos(FLOFile);
i:=Byte('~');
SEEK(FLOFile,FLONamePos);
BlockWRITE(FLOFile,i,1);
SEEK(FLOFile,CurrPos);
END;
GOTO RdFlo;
END;
END ELSE
BEGIN
Abort:
Inc(BadXFers);
IF XFerFlag=AbortXfer THEN
BEGIN
IF FileRec(FloFile).mode<>fmClosed THEN CLOSE(FloFile);
UnMarkNodeBusy(BusyFile);
Exit;
END;
END;
END;
END;
IF XFerFlag=SendRspFile THEN
BEGIN
DoAfter:=DeleteAfter;
FLOFlag:=False;
SAddress:=Call;
Call:=OAddress;
AddTpl(RspFile,'FOOT',TempSr);
Call:=SAddress;
TxFName:=RspFile;
OutboundName:=RspFile;
IF Cfg.Request.RspAsPkt THEN Goto SendIt ELSE GOTO SendIt2;
END;
HoldName:=HoldAreaPath(Call,False);
IF NOT FLOFlag THEN {!}
BEGIN
IF IsCaller THEN ch:='D' ELSE ch:='H';
IF OutboundName='' THEN OutboundName:=HoldFileName(Call,False)+ch+'UT';
ExtFlags[3]:='O';
END ELSE
BEGIN
NxtOut:
ch:=OutBoundName[Length(OutBoundName)-2];
i:=POS(ch,ExtFlags);
IF i<NUMFLAGS THEN
BEGIN
OutBoundName[Length(OutBoundName)-2]:=ExtFlags[i+1];
IF (ExtFlags[i+1]='H') And (IsCaller) THEN GOTO NxtOut;
END ELSE
IF NOT FLOFlag THEN
BEGIN
ExtFlags[3]:='F';
IF IsCaller THEN ch:='D' ELSE ch:='H';
OutBoundName:=ForceExtension(OutBoundName,ch+'LO');
FLOFlag:=TRUE;
END ELSE
BEGIN
UnMarkNodeBusy(BusyFile);
NextAka:
Inc(AkaNum);
IF (AkaNum<=MaxAddresses) And (RemAka[AkaNum].Zone<>0) THEN
BEGIN
Call:=RemAka[AkaNum];
AddLog(':','Sending to AKA: '+Address2Str(Call));
XFerFlag:=InitialXfer;
GOTO DoItAgain;
END;
OutBoundName:='';
TxFName:='';
Integer(TxBuf^):=0;
FLOFlag:=FALSE;
EXIT;
END;
END;
SendIt:
IF OutBoundName<>'' THEN
BEGIN
IF NOT ExistFile(OutBoundName) THEN GOTO NxtOut;
IF FLOFlag THEN GOTO RDFLO;
TxFName:=OutBoundName;
ASSIGN(TxFile,TxFName); FileMode:=ShareRead+ShareDenyW;
RESET(TxFile,1);
IF IoResult=5 THEN
BEGIN
AddLog('!','Access denied to: '+OutboundName);
GOTO NxtOut;
END;
FindFirst(TxFName,AnyFile,f);
FindClose(f);
ShowCurrentFileName(TxFName,0,f.size,95,FALSE);
UnPackTime(f.time,dt);
WITH dt DO
BEGIN
s:=InventPktName+#0+Long2Str(f.size)+' '+OctalL(GetUnixDate(year,month,day,hour,min,sec))+' 00'+#0;
END;
Move(s[1],TxBuf^,Length(s));
DoAfter:=DeleteAfter;
TxLen:=f.Size;
TxDt1.d:=Today;
TxDt1.t:=CurrentTime;
END ELSE
BEGIN
RdFLO:
IF FileRec(FLOFile).Mode=fmclosed THEN
BEGIN
BadXfers:=0;
ASSIGN(FLOFile,OutBoundName); FileMode:=ShareRW+ShareDenyW;
RESET(FLOFile,1);
IF IORESULT<>0 THEN GOTO NxtOut;
END;
FLONamePos:=FilePos(FLOFile);
i:=0;
ReadLine(FLOFile,TxFName);
IF (EoF(FLOFile)) AND (TxFName='') THEN
BEGIN
CLOSE(FLOFile);
IF BadXFers=0 THEN DeleteFile(OutBoundName);
GOTO NxtOut;
END;
IF TxFName<>'' THEN
BEGIN
CASE TxFName[1] OF
'~',
';' : GOTO RdFLO;
TruncAfter,
DeleteAfter,
ShowDeleteAfter : BEGIN
DoAfter:=TxFName[1];
Delete(TxFName,1,1);
END;
ELSE DoAfter:=NothingAfter;
END;
END ELSE
GOTO RDFLO;
SendIt2:
s:=JustFileName(TxFName)+#0;
Move(s[1],TxBuf^,Length(s));
IF TxFName<>'' THEN
BEGIN
IF XFerFlag=AbortXFer THEN GOTO Abort;
IF NOT isCaller AND ((CurrentEvent.Typ AND etNoFiles)<>0) AND
(StUpCase(Copy(TxFName, 1, Length(Cfg.Outbound)))<>StUpCase(Cfg.Outbound)) THEN
BEGIN
Inc(BadXFers);
GOTO RDFLO;
END;
ASSIGN(TxFile,TxFName); FileMode:=ShareRead+ShareDenyW;
RESET(TxFile,1);
IF IORESULT<>0 THEN GOTO SkipName;
FindFirst(TxFName,AnyFile,f);
FindClose(f);
ShowCurrentFileName(TxFName,0,f.size,95,FALSE);
i:=Length(s);
UnPackTime(f.time,dt);
WITH dt DO
BEGIN
s:=Long2Str(f.Size)+' '+OctalL(GetUnixDate(year,month,day,hour,min,sec))+' 00'+#0;
END;
MOVE(s[1],BufferType(TxBuf^)[i],Length(s));
TxDt1.d:=Today;
TxDt1.t:=CurrentTime;
TxLen:=f.Size;
END;
END;
{$IFDEF JDebug}
FastWrite('END GetFName ',1,1,7);
{$ENDIF}
END;
PROCEDURE TxByte(c: Byte);
LABEL
FallThrough1;
BEGIN
CASE c OF
Cr : IF LastSent=Integer('@') THEN GOTO FallThrough1;
Dle,
Xon,
XOff: BEGIN
FallThrough1:
ComPort^.WriteByte(Dle, False);
c:=c XOR $40;
END;
END;
LastSent:=c;
ComPort^.WriteByte(c, False);
END;
PROCEDURE SendPkt32(Buf: Pointer; Len: Word; Typ: Integer);
VAR
crc32 : LongInt;
i : Word;
BEGIN
{$IFDEF JDebug}
FastWrite('SendPkt32 ',1,1,7);
{$ENDIF}
ShowErrorCheckingMethod('J-Send CRC32',False);
ComPort^.WriteByte(Dle, False);
ComPort^.WriteByte(PktStrtChr32 Xor $40, False);
Crc32:=$ffffffff;
IF Len>0 THEN
BEGIN
FOR i:=0 To Len DO
TxByte(BufferType(Buf^)[i]);
FOR i:=0 To Len DO
Crc32:=UpdCrc32(BufferType(Buf^)[i],Crc32);
END;
ComPort^.WriteByte(Byte(Typ), False);
Crc32:=UpdCrc32(Byte(Typ),Crc32);
ComPort^.WriteByte(Dle, False);
ComPort^.WriteByte(PktEndChr Xor $40, False);
TxByte(BYTE(Crc32 Shr 24));
TxByte(BYTE(Crc32 Shr 16));
TxByte(BYTE(Crc32 Shr 8));
TxByte(BYTE(Crc32));
ComPort^.FlushTx;
{$IFDEF JDebug}
FastWrite('END SendPkt32 ',1,1,7);
{$ENDIF}
END;
PROCEDURE SendPkt(Buf: Pointer; Len: Word; Typ: Integer);
VAR
i, Crc16 : Word;
BEGIN
LastSent:=0;
IF ((SharedCap And CanCrc32)<>0) AND (Typ=BlkPkt) THEN
SendPkt32(Buf,Len,Typ)
ELSE
BEGIN
{$IFDEF JDebug}
FastWrite('SendPkt16 ',1,1,7);
{$ENDIF}
ShowErrorCheckingMethod('J-Send CRC16',False);
ComPort^.WriteByte(Dle, False);
ComPort^.WriteByte(PktStrtChr Xor $40, False);
Crc16:=0;
IF Len>0 THEN
BEGIN
FOR i:=0 To Len DO
TxByte(BufferType(Buf^)[i]);
FOR i:=0 To Len DO
Crc16:=UpdCrc16(BufferType(Buf^)[i],Crc16);
END;
ComPort^.WriteByte(Byte(Typ), False);
Crc16:=UpdCrc16(Byte(Typ),Crc16);
ComPort^.WriteByte(Dle, False);
ComPort^.WriteByte(PktEndChr XOR $40, False);
Crc16:=UpdCrc16(0,Crc16);
Crc16:=UpdCrc16(0,Crc16);
TxByte(Hi(Crc16));
TxByte(Lo(Crc16));
ComPort^.FlushTx;
{$IFDEF JDebug}
FastWrite('SendPkt16 ',1,1,7);
{$ENDIF}
END;
IF (TxFName<>'') AND (FileRec(TxFile).Mode<>fmClosed) THEN
BEGIN
ShowCurrentByte(FilePos(TxFile),False);
IF Len>3 THEN Dec(Len,3);
IF Typ=BLKPKT THEN ShowBlockSize(Len,False);
END;
END;
FUNCTION ProcFName: LongInt;
VAR
dt : DateTime;
SRec : SearchRec;
Bytes, Power,
FileStart : LongInt;
i : BYTE;
ok : INTEGER;
BAddress : TFidoAddress;
Found : Boolean;
linebuf,
fileinfo : PathStr;
BadWaZOOFile: PSimpDB;
BadWaZooRec : TBadWaZoo;
BEGIN
{$IFDEF JDebug}
FastWrite('ProcFName ',1,1,7);
{$ENDIF}
RXFname:='';
RxFileTime:=0;
i:=0;
WHILE BufferType(RxBuf^)[i]<>0 DO
BEGIN
RxFName:=RxFName+Char(BufferType(RxBuf^)[i]);
Inc(i);
END;
Inc(i);
FileInfo:='';
WHILE BufferType(RxBuf^)[i]<>0 DO
BEGIN
FileInfo:=FileInfo+Char(BufferType(RxBuf^)[i]);
Inc(i);
END;
Inc(i);
SharedCap:=BufferType(RxBuf^)[i] And (OURCAP or CANFREQ);
IF Byte(RxBuf^)=0 THEN
BEGIN
ProcFName:=0;
Exit;
END;
Replace(RxFName, ' ', '_', 0);
LineBuf:=StLoCase(RxFName);
RxLen:=-1;
IF Pos(' ',FileInfo)=0 THEN
BEGIN
AddLog('!','No file size in header');
ProcFName:=-1;
Exit;
END ELSE
BEGIN
Val(Copy(FileInfo,1,Pos(' ',FileInfo)-1),RxLen,ok);
power := 1;
WHILE FileInfo[Length(FileInfo)]<>' ' DO
Dec(Byte(FileInfo[0]));
Dec(Byte(FileInfo[0]));
FOR ok := Length(FileInfo) DOWNTO Pos(' ',FileInfo)+1 DO
BEGIN
RxFileTime:=RxFileTime+(Ord(FileInfo[ok])-$30)*power;
power := power * 8;
END;
WITH dt Do
BEGIN
UnPackUnix(RxFileTime,year,month,day,hour,min,sec);
PackTime(dt,RxFileTime);
END;
END;
Found:=False;
IF Reqstarted THEN BAddress:=ReqAddress ELSE BAddress:=OAddress;
New(BadWaZOOFile, Open(StartPath+PoPBadWaZooFileName, SizeOf(TBadWaZoo), False));
IF BadWaZOOFile<>Nil THEN
BEGIN
WHILE NOT Found AND BadWaZOOFile^.NextRec(BadWaZOORec, Keep) DO
BEGIN
IF CmpAdr(BadWaZooRec.Address,BAddress) And
(StUpCase(BadWaZooRec.FName)=StUpCase(LineBuf)) THEN
Found:=True
ELSE
BadWaZooFile^.Unlock(BadWaZooFile^.FilePos-1);
END;
IF Found THEN
BEGIN
BadWaZooFile^.DelRec(BadWaZooRec,BadWaZooFile^.FilePos-1);
END;
Dispose(BadWaZOOFile, Close);
Found:=((Found) AND (BadWaZooRec.FSize=RxLen) AND (BadWaZooRec.FTime=RxFileTime));
END;
IF Found THEN
BEGIN
RenameFile(Cfg.Inbound[BadWaZooRec.NodeStat]+BadWaZooRec.NewName, Cfg.Inbound[GlobNodeStat]+LineBuf);
RxFName:=LineBuf;
END ELSE
BEGIN
FINDFIRST(Cfg.Inbound[GlobNodeStat]+LineBuf, AnyFile, Srec);
IF DOSERROR = 0 THEN
BEGIN
IF (Srec.size = RxLen) AND (RxFileTime = Srec.Time) THEN
BEGIN
ShowError('Already have: ' + LineBuf,False,true,true);
ProcFName:=-1;
FindClose(Srec);
Exit;
END;
RxFName:=JustFileName(UniqueName(cfg.inbound[GlobNodeStat]+LineBuf));
ShowError('File renamed from: '+LineBuf+' to: '+RxFName, False, True, True);
END;
FindClose(Srec);
END;
Assign(RxFile,Cfg.Inbound[GlobNodeStat]+RxFName); FileMode:=ShareRW+ShareDenyRW;
Reset(RxFile,1);
IF IOResult<>0 THEN ReWrite(RxFile,1) ELSE Seek(RxFile, FileSize(RxFile));
FileStart:=FileSize(RxFile);
ShowCurrentFileName(RxFName,FileStart,RxLen,95,True);
Bytes:=RxLen-FileStart+10240;
IF Bytes>DiskAvail THEN
BEGIN
AddLog('!','Not enough disk space on drive');
Close(RxFile);
ProcFName:=-1;
Exit;
END;
RxDt1.d:=Today;
RxDt1.t:=CurrentTime;
ProcFName:=FileStart;
{$IFDEF JDebug}
FastWrite('END ProcFName ',1,1,7);
{$ENDIF}
END;
FUNCTION RcvRawByte: Integer;
VAR
TimeVal : EventTimer;
BEGIN
IF ComPort^.Keypressed THEN
BEGIN
RcvRawByte:=ComPort^.ReadByte;
Exit;
END;
IF NOT ComPort^.Carrier THEN
BEGIN
RcvRawByte:=NOCARRIER;
Exit;
END;
IF (WaitFlag=0) AND (NOT ComPort^.KeyPressed) THEN
BEGIN
RcvRawByte:=BUFEMPTY;
Exit;
END;
NewTimerSecs(TimeVal, TimeOutSecs);
WHILE NOT ComPort^.Keypressed DO
BEGIN
IF NOT ComPort^.Carrier THEN
BEGIN
RcvRawByte:=NOCARRIER;
Exit;
END;
IF TimerExpired(TimeVal) THEN
BEGIN
RcvRawByte:=BUFEMPTY;
Exit;
END;
{ GiveUpTime;}
END;
RcvRawByte:=ComPort^.ReadByte;
END;
FUNCTION RxByte: Integer;
VAR
c : Integer;
w : Byte;
BEGIN
c:=RcvRawByte;
IF Lo(c)=DLE THEN
BEGIN
w:=WaitFlag;
WaitFlag:=1;
c:=RcvRawByte;
IF c>=0 THEN
BEGIN
c:=c XOR $40;
CASE c OF
PKTSTRTCHR : c:=PKTSTRT;
PKTSTRTCHR32 : c:=PKTSTRT32;
PKTENDCHR : c:=PKTEND;
END;
END;
WaitFlag:=w;
END;
RxByte:=c;
END;
FUNCTION RcvPkt: Byte;
LABEL
FallThrough;
VAR
i : Byte;
c : Integer;
PktCrc : LongInt;
BEGIN
{$IFDEF JDebug}
FastWrite('RcvPkt ',1,1,7);
{$ENDIF}
IF GotESC THEN
BEGIN
AddLog('!','Keyboard Escape');
RcvPkt:=HALTPKT;
Exit;
END;
WaitFlag:=0;
IF p=$ffff THEN
BEGIN
REPEAT
c:=RxByte;
UNTIL (c<0) And (c<>PKTEND);
CASE c OF
PKTSTRT : BEGIN
ShowErrorCheckingMethod('J-Receive CRC16',True);
RXCrc32:=False;
p:=0;
rCrc16:=0;
END;
PKTSTRT32:BEGIN
ShowErrorCheckingMethod('J-Receive CRC32',True);
RXCrc32:=True;
p:=0;
rCrc32:=$ffffffff;
END;
NOCARRIER:BEGIN
AddLog('!','No Carrier');
RcvPkt:=HALTPKT;
Exit;
END;
ELSE BEGIN
RcvPkt:=NOPKT;
Exit;
END;
END;
END;
c:=RxByte;
WHILE (c>=0) AND (p<RxBufMax) DO
BEGIN
BufferType(RxBuf^)[p]:=Byte(c);
IF RxCrc32 THEN rCrc32:=UpdCrc32(Byte(c),rCrc32) ELSE rCrc16:=UpdCrc16(Byte(c),rCrc16);
Inc(p);
c:=RxByte;
END;
CASE c OF
PKTEND : BEGIN
IF Not RxCrc32 THEN
BEGIN
rCrc16:=UpdCrc16(0,rCrc16);
rCrc16:=UpdCrc16(0,rCrc16);
END;
WaitFlag:=1;
PktCrc:=0;
FOR i:=1 TO 2+2*Byte(RxCrc32) DO
BEGIN
c:=RxByte;
IF c<0 THEN Goto FallThrough;
PktCrc:=LongInt(PktCrc Shl 8) + Byte(c);
END;
IF ((RxCrc32) And (PktCrc=rCrc32)) Or (PktCrc=rCrc16) THEN
BEGIN
Dec(p);
RxBlkLen:=p;
RcvPkt:=BufferType(RxBuf^)[p];
IF p>4 THEN Dec(p,4);
IF BufferType(RxBuf^)[p+4]=BLKPKT THEN ShowBlockSize(p,True);
p:=$ffff;
Exit;
END ELSE
ShowError('CRC Error',True,False,True);
Goto FallThrough;
END;
BUFEMPTY: BEGIN
RcvPkt:=NOPKT;
Exit;
END;
PKTSTRT : BEGIN
RxCrc32:=False;
p:=0;
rCrc16:=0;
RcvPkt:=BADPKT;
Exit;
END;
PKTSTRT32:BEGIN
RxCrc32:=True;
p:=0;
rCrc32:=$ffffffff;
RcvPkt:=BADPKT;
Exit;
END;
ELSE BEGIN
FallThrough:
IF c=NOCARRIER THEN
BEGIN
AddLog('!','No carrier');
RcvPkt:=HALTPKT;
END ELSE
BEGIN
RcvPkt:=BADPKT;
END;
p:=$ffff;
Exit;
END;
END;
END;
PROCEDURE RxClose(XFerFlag: Word);
VAR
NameBuf : PathStr;
BadWaZooFile: PSimpDB;
BadWaZooRec : TBadWaZoo;
BAddress : TFidoAddress;
BEGIN
{$IFDEF JDebug}
FastWrite('RxClose ',1,1,7);
{$ENDIF}
IF RxFileTime<>0 THEN SetFTime(RxFile,RxFileTime);
IF FileRec(RxFile).mode<>fmClosed THEN CLOSE(RxFile);
IF XFerFlag=FAILEDXFER THEN
BEGIN
IF RxPos>0 THEN
BEGIN
AddLog('!','File '+RxFName+' aborted - saving resume information');
NameBuf:=UniqueName(Cfg.Inbound[GlobNodeStat]+'BADWAZOO.000');
RenameFile(Cfg.Inbound[GlobNodeStat]+RxFName,NameBuf);
IF Reqstarted THEN BAddress:=ReqAddress ELSE BAddress:=OAddress;
New(BadWaZOOFile, Open(StartPath+PoPBadWaZooFileName, SizeOf(TBadWaZoo), True));
IF BadWaZOOFile<>NIL THEN
BEGIN
FillChar(BadWaZooRec, SizeOf(BadWaZooRec), 0);
WITH BadWaZooRec DO
BEGIN
Address:=BAddress;
FName:=JustFileName(RxFName);
FSize:=RxLen;
FTime:=RxFileTime;
NewName:=StUpCase(JustFileName(NameBuf));
NodeStat:=GlobNodeStat;
END;
BadWaZooFile^.AddRec(BadWazooRec);
Dispose(BadWaZooFile, Close);
END ELSE
AddLog('!', 'Error opening: '+PoPBadWaZooFileName);
END ELSE
DeleteFile(Cfg.Inbound[GlobNodeStat]+RxFName);
END;
{$IFDEF JDebug}
FastWrite('END RxClose ',1,1,7);
{$ENDIF}
END;
PROCEDURE EndBatch;
LABEL
Reject;
VAR
i : Byte;
Done : Boolean;
TimeOuts : Word;
TimeVal, BrainDead : EventTimer;
BEGIN
{$IFDEF JDebug}
FastWrite('EndBatch ',1,1,7);
{$ENDIF}
Done:=False; TimeOuts:=0;
NewTimerSecs(BrainDead, 120);
GOTO Reject;
WHILE Not Done AND Not TimerExpired(BrainDead) DO
BEGIN
CASE RcvPkt OF
NOPKT,
BADPKT : BEGIN
IF TimerExpired(TimeVal) THEN
BEGIN
Inc(TimeOuts);
IF TimeOuts>2 THEN Done:=True ELSE GOTO Reject;
END;
END;
HALTPKT,
HALTACKPKT: Done:=True;
ELSE BEGIN
TimeOuts:=0;
Reject:
SendPkt(Nil,0,HALTPKT);
NewTimerSecs(TimeVal, TimeoutSecs);
END;
END;
END;
FOR i:=0 TO 9 DO
SendPkt(Nil,0,HALTACKPKT);
WHILE NOT ComPort^.OutEmpty DO
{ GiveUpTime};
{$IFDEF JDebug}
FastWrite('END EndBatch ',1,1,7);
{$ENDIF}
END;
PROCEDURE MarkDone(CONST Name: PathStr);
VAR
f : FILE;
i : LONGINT;
s:STRING;
done:BOOLEAN;
Ch : Char;
BEGIN
{$IFDEF JDebug}
FastWrite('MarkDone ',1,1,7);
{$ENDIF}
Assign(f, Name); FileMode:=ShareRW+ShareDenyRW;
Reset(f, 1);
i:=0;
Done:=False;
REPEAT
i:=FilePos(f);
ReadLine(f,s);
IF Copy(s,1,1)<>';' THEN
BEGIN
Seek(f,i);
ch:=';';
BlockWrite(f,ch,1);
Done:=True;
END;
UNTIL Done Or (EoF(f));
Close(f);
{$IFDEF JDebug}
FastWrite('END MarkDone ',1,1,7);
{$ENDIF}
END;
FUNCTION GetFileReq(ReqStarted: Boolean): Boolean;
VAR
GotOne : Boolean;
LineBuf,
ReqName : PathStr;
ReqFile : File;
BEGIN
{$IFDEF JDebug}
FastWrite('GetFileReq ',1,1,7);
{$ENDIF}
GetFileReq:=False;
GotOne:=False;
WHILE NOT GotOne AND (ReqAkaNum<=MaxAddresses) AND ((ReqAkaNum=0) OR (RemAka[ReqAkaNum].Zone<>0)) DO
BEGIN
ReqName:=HoldFileName(ReqAddress,False)+'REQ';
IF ExistFile(ReqName) THEN
BEGIN
IF ReqStarted THEN MarkDone(ReqName);
IF NOT (WzFreq IN RemHello.Capabilities) THEN { Capabilities?? }
BEGIN
AddLog('!','File request declined');
ReqAkaNum:=MaxAddresses+1;
Exit;
END ELSE
IF (SharedCap AND CANFREQ)=0 THEN
BEGIN
AddLog('!','Remote can''t handle file request');
ReqAkaNum:=MaxAddresses+1;
Exit;
END ELSE
BEGIN
Assign(ReqFile, ReqName); FileMode:=ShareRead+ShareDenyW;
Reset(ReqFile,1);
IF IOResult=0 THEN
BEGIN
WHILE NOT EoF(ReqFile) AND NOT GotOne DO
BEGIN
ReadLine(ReqFile, LineBuf);
IF (Copy(LineBuf,1,1)<>';') And (LineBuf<>'') THEN
BEGIN
AddLog('+','Requesting: '+LineBuf);
LineBuf:=LineBuf+#0+Char(SharedCap);
Move(LineBuf[1],RxBuf^,Length(LineBuf));
GotOne:=True;
END;
END;
Close(ReqFile);
IF NOT GotOne THEN DeleteFile(ReqName);
END;
END;
END;
IF NOT GotOne THEN
BEGIN
Inc(ReqAkaNum);
IF (ReqAkaNum<=MaxAddresses) AND (RemAka[ReqAkaNum].Zone<>0) THEN
BEGIN
ReqAddress:=RemAka[ReqAkaNum];
ReqStarted:=False;
END;
END;
END;
GetFileReq:=GotOne;
{$IFDEF JDebug}
FastWrite('END GetFileReq ',1,1,7);
{$ENDIF}
END;
FUNCTION GetReqName: Boolean;
VAR
Tmp : PathStr;
dt : DateTime;
TransTime : LongInt;
BEGIN
{$IFDEF JDebug}
FastWrite('GetReqName ',1,1,7);
{$ENDIF}
DoAfter:=NothingAfter;
GetReqName:=False;
REPEAT
TxFName:=GetNextFileToSend(FreeArea);
IF TxFName<>'' THEN
BEGIN
IF (MaxReqFiles>0) OR (FreeArea=faTotally) THEN
BEGIN
IF (MaxReqBytes-ReqSr.Size>=0) OR (FreeArea=faTotally) THEN
BEGIN
TransTime:=ReqSr.Size DIV (ComPort^.GetBaudRate DIV 10);
IF (TimeToNoMoreRequest>TransTime) AND
((MaxReqTime>TransTime) OR (FreeArea=faTotally)) THEN
BEGIN
Assign(TxFile, TxFName); FileMode:=ShareRead+ShareDenyW;
Reset(TxFile,1);
IF IOResult=5 THEN
AddLog('!','Access denied to: '+TxFName)
ELSE
Break;
END ELSE
BEGIN
AddTpl(rspfile,'TIMEOUT',reqsr);
AddLog('#','Not enough time (Lft: '+
TimeToTimeString('Hh:mm:ss',Min(MaxReqTime,TimeToNoMoreRequest))+
'/Tfr: '+
TimeToTimeString('Hh:mm:ss',TransTime)+'): '+TxFName);
END;
END ELSE
BEGIN
AddTpl(RspFile,'TOOBIG',ReqSr);
AddLog('#','File too big ('+Long2Str(MaxReqBytes)+'): '+TxFName);
END;
END ELSE
BEGIN
AddTpl(rspfile,'TOOMANY',reqsr);
AddLog('#','Too many files '+TxFName);
END ;
END;
UNTIL TxFName='';
IF TxFName<>'' THEN
BEGIN
UnPackTime(ReqSr.time,dt);
WITH dt DO
BEGIN
Tmp:=JustFileName(TxFName)+#0+Long2Str(FileSize(TxFile))+' '+OctalL(GetUnixDate(year,month,day,hour,min,sec))+' 00'+#0;
END;
Move(Tmp[1],TxBuf^,Length(Tmp));
TxLen:=ReqSr.Size;
ShowCurrentFileName(TxFName,0,ReqSr.Size,95,False);
TxDt1.d:=Today;
TxDt1.t:=CurrentTime;
GetReqName:=True;
END;
{$IFDEF JDebug}
FastWrite('END GetReqName ',1,1,7);
{$ENDIF}
END;
BEGIN
ComPort^.SetXOn(Off);
SharedCap:=0; TotalBytes:=0;
OURCAP:=CANCRC32;
IF ((CurrentEvent.typ AND etRequests)=etRequests) AND (ReqOk) AND
(NOT NodesRec.DisallowReq) THEN OurCap:=OurCap OR CANFREQ;
IF NOT GetMemCheck(TxBuf,4096) THEN Exit;
IF NOT GetMemCheck(RxBuf,5000) THEN
BEGIN
FreeMem(TxBuf, 4096);
Exit;
END;
TxFName:='';
RxFName:='';
RxBufMax:=4096;
AkaNum:=0; ReqAkaNum:=0;
MustWriteDRI:=False;
OAddress:=Call;
ReqAddress:=Call;
TxInhibit:=False;
LastRPosTime:=0; XmitRetry.StartTics:=0;
TimeOutSecs:=40960 DIV ComPort^.GetBaudRate;
IF TimeOutSecs<10 THEN TimeOutSecs:=10;
NewTimerSecs(BrainDead, 120);
TxBlkMax:=ComPort^.GetBaudRate DIV 300 * 128;
IF TxBlkMax>BUFMAX THEN TxBlkMax:=BUFMAX;
TxBlkLen:=TxBlkMax;
GoodBytes:=0; GoodNeeded:=0;
SendingReq:=False; FSent:=0;
p:=$ffff;
RxCRC32:=FALSE;
XState:=XSENDFNAME;
FileRec(FLOFile).Mode:=FmClosed;
FileRec(TxFile).Mode:=FmClosed;
FileRec(RxFile).Mode:=FmClosed;
GetFName(INITIALXFER);
DiskAvail:=DriveFree(Byte(Cfg.Inbound[GlobNodeStat][1])-64);
RPosRetry.StartTics:=0; RPosCount:=0;
AttemptingReq:=False; ReqStarted:=False;
RState:=RRCVFNAME;
StartTime.d := Today;
StartTime.t := CurrentTime;
REPEAT
{$IFDEF JDebug}
FastWrite('Main loop XS='+Long2Str(XState)+' RS='+Long2Str(RState) ,1,1,7);
{$ENDIF}
IF TimerExpired(BrainDead) THEN
BEGIN
AddLog('!','Other end died');
GOTO GiveUp;
END;
IF (XMitRetry.StartTics>0) And (TimerExpired(XMitRetry)) THEN
BEGIN
ShowError('TimeOut',False,False,False);
XmitRetry.StartTics:=0;
CASE XState OF
XRCVFNACK : XState:=XSENDFNAME;
XRCVFRNAKACK: XState:=XSENDFREQNAK;
XRCVEOFACK : BEGIN
TxPos:=LastTx;
Seek(TxFile,TxPos);
IF IOResult<>0 THEN
BEGIN
ShowError('Seek Error '+TxFName,False,True,True);
GOTO GiveUp;
END;
XState:=XSENDBLK;
END;
END; {case}
END;
CASE XState OF
XSENDBLK: BEGIN
IF NOT TxInhibit THEN
BEGIN
LongInt(TxBuf^):=TxPos;
LastTx:=TXPos;
BlockRead(TxFile, BufferType(TxBuf^)[4], TxBlkLen, BlkLen);
Inc(TxPos,BlkLen);
SendPkt(TxBuf, BlkLen+3, BLKPKT);
FSent:=1;
IF (TxPos>=TxLen) OR (BlkLen<TxBlkLen) THEN
BEGIN
NewTimerSecs(XMitRetry, TimeOutSecs);
XState:=XRCVEOFACK;
END ELSE
NewTimerSecs(BrainDead, 120);
Inc(GoodBytes,TxBlkLen);
IF (TxBlkLen<TxBlkMax) AND (GoodBytes>=GoodNeeded) THEN
BEGIN
TxBlkLen:=TxBlkLen SHL 1;
GoodBytes:=0;
END;
END;
END;
XSENDFNAME: BEGIN
BlkLen:=0;
WHILE BufferType(TxBuf^)[BlkLen]<>0 DO
Inc(BlkLen);
Inc(BlkLen);
WHILE BufferType(TxBuf^)[BlkLen]<>0 DO
Inc(BlkLen);
Inc(BlkLen);
BufferType(TxBuf^)[BlkLen]:=OURCAP;
SendPkt(TxBuf, BlkLen, FNAMEPKT);
NewTimerSecs(XMitRetry, TimeOutSecs);
XState:=XRCVFNACK;
END;
XSENDFREQNAK: BEGIN
SendPkt(Nil, 0, FREQNAKPKT);
NewTimerSecs(XMitRetry, TimeOutSecs);
XState:=XRCVFRNAKACK;
END;
END;
PktType:=RcvPkt;
WHILE PktType<>NOPKT DO
BEGIN
IF PktType<>BADPKT THEN NewTimerSecs(BrainDead, 120);
CASE PktType OF
BADPKT,
BLKPKT : BEGIN
IF RState=RRCVBLK THEN
BEGIN
IF (PktType=BADPKT) Or (LongInt(RxBuf^)<>RxPos) THEN
BEGIN
IF PktType=BLKPKT THEN
BEGIN
IF LongInt(RxBuf^)<LastBlkPos THEN
BEGIN
RPosRetry.StartTics:=0; RPosCount:=0;
END;
LastBlkPos:=LongInt(RxBuf^);
END;
IF {(RPosRetry>0) And} (TimerExpired(RPosRetry)) THEN
BEGIN
IF RPosCount>4 THEN
BEGIN
IF (XState<>0) And Not (IsCaller) And Not (TxInhibit) THEN
BEGIN
TxInhibit:=True;
AddLog('!','Dropping to one-way xfer');
END ELSE
GOTO GiveUp;
RPosCount:=0;
END;
Inc(RPosCount);
IF RPosCount=1 THEN Time(RPosStTime);
ShowError('Bad packet at '+Long2Str(RxPos),TRUE,FALSE,TRUE);
LongInt(RxBuf^):=RxPos;
MOVE(RPosStTime,BufferType(RxBuf^)[4],4);
SendPkt(RxBuf,7,RPOSPKT);
NewTimerSecs(RPosRetry, TimeOutSecs DIV 2);
END;
END ELSE
BEGIN
LastBlkPos:=RxPos;
RPosRetry.StartTics:=0; RPosCount:=0;
Dec(RxBlkLen,4);
BlockWrite(RxFile,BufferType(RxBuf^)[4],RxBlkLen);
i:=IORESULT;
IF i<>0 THEN
BEGIN
AddLog('!','Error '+Long2Str(i)+' writing '+RxFName);
GOTO GiveUp;
END;
ShowCurrentByte(FilePos(RxFile),True);
Dec(DiskAvail, RxBlkLen);
Inc(RxPos,RxBlkLen);
IF RxPos>=RxLen THEN
BEGIN
RxClose(GOODXFER);
FileReceived(JustFileName(RxFName),'J'+CrcStr(SharedCap AND CANCRC32=CANCRC32),TRUE);
Dec(RxLen,RxStPos);
Inc(TotalBytes, RxLen);
RState:=RRCVFNAME;
END;
END;
END;
IF RState=RRCVFNAME THEN SendPkt(NIL,0,EOFACKPKT);
END;
FNAMEPKT : BEGIN
IF RState=RRCVFNAME THEN
BEGIN
RxPos:=ProcFName;
RxStPos:=RxPos;
END;
IF (RxFname='') AND GetFileReq(ReqStarted) THEN
BEGIN
i:=0;
WHILE BufferType(RxBuf^)[i]<>0 DO
Inc(i);
SendPkt(RxBuf,i+1,FREQPKT);
AttemptingReq:=TRUE;
ReqStarted:=FALSE;
END ELSE
BEGIN
IF AttemptingReq THEN
BEGIN
AttemptingReq:=FALSE;
ReqStarted:=TRUE;
END;
LongInt(RxBuf^):=RxPos;
BufferType(RxBuf^)[4]:=SharedCap;
SendPkt(RxBuf,4,FNACKPKT);
IF RxPos>-1 THEN
BEGIN
IF RxFName<>'' THEN RState:=RRCVBLK ELSE RState:=RDONE;
END ELSE
AddLog('+','Refusing '+JustFileName(RxFName));
IF RState=0 THEN TxInhibit:=False;
IF (XState=0) And (RState=0) THEN GOTO BreakOut;
END;
END;
FNACKPKT: BEGIN
IF XState=XRCVFNACK THEN
BEGIN
XmitRetry.StartTics:=0;
IF TxFName<>'' THEN
BEGIN
{shared cap}
IF RxBlkLen>4 THEN SharedCap:=BufferType(RxBuf^)[4] AND (OURCAP or CANFREQ);
TxPos:=LongInt(RxBuf^);
IF TxPos>-1 THEN
BEGIN
IF txPos<>0 THEN
BEGIN
ShowCurrentFileName(TxFName,TxPos,FileSize(TxFile),95,FALSE);
END;
TxStPos:=TxPos;
Seek(TxFile, TxPos);
IF IOResult<>0 THEN Goto GiveUp;
XState:=XSENDBLK;
END ELSE
BEGIN
Inc(BadXFers);
ShowError('Remote refused '+JustFileName(TxFName),False,True,False);
IF SendingReq THEN
BEGIN
SendingReq:=GetReqName;
IF Not SendingReq THEN GetFName(GoodXFer);
END ELSE
BEGIN
DoAfter:=NothingAfterRefuse;
GetFName(GoodXFer);
END;
XState:=XSENDFNAME;
END;
END ELSE
BEGIN
XState:=XDONE;
END;
END;
IF XState+RState=0 THEN Goto BreakOut;
END;
FREQPKT : BEGIN
IF XState=XRCVFNACK THEN
BEGIN
XmitRetry.StartTics:=0;
i:=0;
WHILE BufferType(RxBuf^)[i]<>0 DO
INC(i);
SharedCap:=BufferType(RxBuf^)[i+1] AND (OURCAP or CANFREQ);
IF (MaxReqFiles>0) THEN
BEGIN
fn:=MakeReqFileName(Cfg.Addresses[Cfg.MainAdrNum].Net, Cfg.Addresses[Cfg.MainAdrNum].Node, GlobNodeStat);
MOVE(s[1],TxBuf^,Length(s));
New(ReqFile, Init(fn, SCreate, 128));
IF ReqFile<>NIL THEN
BEGIN
Move(RxBuf^,s[1],i);
s[0]:=Char(i);
ReqFile^.WriteLn(s);
Dispose(ReqFile, Done);
END;
SAddress:=Call;
Call:=OAddress;
IF InitReqFile(Cfg.Addresses[Cfg.MainAdrNum].Net,Cfg.Addresses[Cfg.MainAdrNum].Node) THEN
BEGIN
FillChar(TempSr,SizeOf(TempSr),0);
AddTpl(RspFile,'HEADER',ReqSr);
SendingReq:=GetReqName;
IF NOT SendingReq THEN GetFName(SendRSPFile);
IF TxFName<>'' THEN XState:=XSendFName ELSE XState:=XSendFReqNAK;
END;
Call:=SAddress;
END
ELSE XState:=XSendFReqNAK;
END;
END;
FreqNAKPkt : BEGIN
AttemptingReq:=FALSE;
ReqStarted:=TRUE;
SendPkt(NIL,0,FRNAKACKPKT);
END;
FrNAKACKPkt: BEGIN
IF XState=XRcvFRNAKACK THEN
BEGIN
XmitRetry.StartTics:=0;
GetFName(GoodXFer);
XState:=XSendFName;
END;
END;
EOFACKPKT: BEGIN
IF (XState=XRcvEOFACK) OR (XState=XRcvFNACK) THEN
BEGIN
XmitRetry.StartTics:=0;
IF XState=XRCVEOFACK THEN
BEGIN
FileSent(TxFName,'J'+CrcStr(SharedCap AND CANCRC32=CANCRC32),FALSE);
DEC(TxLen,TxStPos);
Inc(TotalBytes,TxLen);
IF SendingReq THEN
BEGIN
Dec(TimeToNoMoreRequest, ReqSr.Size DIV (ComPort^.GetBaudRate DIV 10));
IF FreeArea=faNoWay THEN
BEGIN
Dec(MaxReqFiles); Dec(MaxReqBytes,ReqSr.Size) ;
Dec(MaxReqTime,ReqSr.Size DIV (ComPort^.GetBaudRate DIV 10));
WITH DRI DO
BEGIN
Inc(NumFiles); Inc(NumBytes, ReqSr.Size);
Inc(UsedTime, ReqSr.Size DIV (ComPort^.GetBaudRate DIV 10));
END;
MustWriteDRI:=True;
END;
INC(TempSr.Attr);
INC(TempSr.Size,ReqSr.Size);
AddTpl(RspFile,'FOUND',ReqSr);
SendingReq:=GetReqName;
IF NOT SendingReq THEN GetFName(GoodXFer);
END ELSE
GetFName(GoodXFer);
END;
IF (TxFName='') And (ExistFile(RspFile)) THEN
BEGIN
GetFName(SendRspFile);
END;
XState:=XSendFName;
END;
END;
RPOSPKT : BEGIN
IF (XState=XSENDBlk) OR (XState=XRCVEOFACK) THEN
IF LongInt(BufferType(RxBuf^)[4])<>LastRPosTime THEN
BEGIN
{$IFDEF OS2}
LastRPosTime:=LongInt(Ptr({Seg(RxBuf^),}Ofs(RxBuf^)+4)^);
{$ELSE}
LastRPosTime:=LongInt(Ptr(Seg(RxBuf^),Ofs(RxBuf^)+4)^);
{$ENDIF}
XmitRetry.StartTics:=0;
ComPort^.PurgeOut;
TxPos:=LongInt(RxBuf^);
LastTx:=TxPos;
Seek(TxFile,TxPos);
IF IORESULT<>0 THEN
BEGIN
AddLog('!','Seek error: '+TxFname);
GOTO GiveUp;
END;
ShowError('Synchronizing '+Long2Str(TxPos),FALSE,FALSE,FALSE);
TxBlkLen:=TxBlkLen SHR 2;
IF TxBlkLen<64 THEN TxBlkLen:=64;
GoodBytes:=0;
INC(GoodNeeded,1024);
IF GoodNeeded>8192 THEN GoodNeeded:=8192;
XState:=XSENDBLK;
END;
END;
HALTACKPKT : ;
HALTPKT : BEGIN
GiveUp:
ShowError('Session aborted',TRUE,TRUE,FALSE);
IF TxFName<>'' THEN GetFName(AbortXFer);
IF RSTATE=RRCVBLK THEN Inc(TotalBytes,(RxPos-RxStPos));
IF RxFName<>'' THEN RxClose(FailedXFer);
GOTO abort;
END;
ELSE
BEGIN
ShowError('Unknown packet type',TRUE,TRUE,TRUE);
GOTO GiveUp;
END;
END;
PktType:=RcvPkt;
END;
{$IFDEF JDebug}
FastWrite('END Main loop XS='+Long2Str(XState)+' RS='+Long2Str(RState) ,1,1,7);
{$ENDIF}
UNTIL (XState=0) And (RState=0);
BreakOut:
Call:=OAddress;
IF FSent=0 THEN
BEGIN
AddLog(':','Nothing to send to '+Address2Str(Call));
END;
Abort:
UnMarkNodeBusy(BusyFile);
IF MustWriteDRI THEN WriteSuckerInfo(DRI);
Call:=OAddress;
TxDt1.t:=CurrentTime;
TxDt1.d:=Today;
Datetimediff(StartTime, TxDt1, Days, Secs);
IF Secs = 0 THEN Secs := 1;
Effektivitet := TotalBytes / Secs / ComPort^.GetBaudRate * 1000;
AddLog('+','Session totals: CPS: '+Long2Str(TotalBytes DIV Secs)+' ('+Long2Str(Totalbytes)+' bytes) Efficiency: '+
Form('###.#',Effektivitet)+'%');
EndBatch;
FreeMem(TxBuf, 4096);
FreeMem(RxBuf, 5000);
END;
END.